<?php
declare (strict_types=1);

namespace app\model;

use app\exception\ModelEmptyException;
use app\exception\ModelException;

/**
 * @mixin \think\Model
 */
class Route extends Model
{

    public function category(): \think\model\relation\BelongsTo
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * @param array $where
     * @param int $limit
     * @return array
     * @throws ModelException
     */
    public function getRouteList(array $where = [], int $limit = 10): array
    {
        try {
            $res = $this->where($where)->paginate($limit);
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->getMsg, $res);

    }

    /**
     * @param array $where
     * @param string[] $order
     * @return array
     * @throws ModelException
     */
    public function getAllRoute(array $where, array $order=['id','asc']): array
    {
        try {
            $res = $this->where($where)->order($order[0],$order[1])->select();
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->getMsg, $res);
    }

    /**
     * @param array $where
     * @return array
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public function getRoute(array $where = [],$with=[]): array
    {
        try {
            $res = $this->with($with)->where($where)->find();
            if (empty($res)) {
                throw new ModelEmptyException();
            }
        } catch (ModelEmptyException $me) {
            throw new ModelEmptyException();
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->getMsg, $res);

    }

    /**
     * @param array $where
     * @return array
     * @throws ModelException
     */
    public function exitRoute(array $where = []): array
    {
        try {
            $res = $this->where($where)->find();
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->getMsg, $res);
    }

    /**
     * @param $param
     * @return array
     * @throws ModelException
     */
    public function addRoute($param): array
    {
        try {
            $res = self::create($param);
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->addMsg, $res);
    }

    /**
     * @param array $where
     * @param array $param
     * @return array
     * @throws ModelException
     */
    public function updateRoute(array $where = [], array $param = []): array
    {
        try {
            $res = self::where($where)->update($param);
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->updateMsg, $res);
    }

    /**
     * @param $where
     * @return array
     * @throws ModelException
     */
    public function softDelRoute($where): array
    {
        try {
            $res = $this->where($where)->update($this->delData);
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->delMsg, $res);
    }

    /**
     * @param $where
     * @return array
     * @throws ModelException
     */
    public function delRoute($where): array
    {
        try {
            $res = $this->where($where)->delete();
        } catch (\Exception $e) {
            throw new ModelException($e->getMessage());
        }
        return dataReturn($this->sucCode, $this->delMsg, $res);
    }


    /**
     * @throws ModelException
     * @throws ModelEmptyException
     */
    public function getRoutes($siteId, $sellerId, $lang): array
    {
        $routes = $this->getAllRoute(['website_id'=>$siteId,'lang'=>$lang,'seller_id'=>$sellerId,'status'=>1],['sort','desc'])['data']->toArray();
        $Website = new Website();
        $websiteDomain = $Website->getWebsite(['id'=>$siteId,'seller_id'=>$sellerId])['data']['domain'];
        $allRoutes = [];
        $cacheRoutes = [];
        foreach ($routes as $er) {

            $fullUrl = htmlspecialchars_decode($er['full_url']);
            // 解析URL
            $info = parse_url($fullUrl);

            $vars = [];
            // 解析参数
            if (isset($info['query'])) { // 解析地址里面参数 合并到vars
                parse_str($info['query'], $vars);
                ksort($vars);
            }

            $path = explode("/", $info['path']);

            if (count($path) != 2) {//必须是完整 url
                continue;
            }

            $path = $info['path'];

            $fullUrl = $path . (empty($vars) ? "" : "?") . http_build_query($vars);

            $url = htmlspecialchars_decode($er['url']);
            if (!isset($cacheRoutes[$path])) {
                $cacheRoutes[$path] = [];
            }
            array_push($cacheRoutes[$path], ['vars' => $vars]);

            if (empty($er['pattern'])) {
                $allRoutes[$url] = $fullUrl;
            } else {
                $allRoutes[$url] = [$fullUrl, [], json_decode($er['pattern'],true)];//[routeUrl,options,patterns]
            }

        }
        cache("routes", $cacheRoutes);

        $fileStr = [
            '<?php',
            'use think\facade\Route;',
            '',
            "Route::domain('$websiteDomain',function(){",
        ];
        $customerStr = [];
        if($lang != "zh"){
            array_push($customerStr,"Route::group('$lang',function(){");
        }else{
            array_push($customerStr,'Route::group(function(){');
        }
        foreach ($allRoutes as $rule => $route) {
            $pattern = '';
            if (is_array($route)) {
                $routeUrl = $route[0];
                if (!empty($route[2])) {
                    $pattern = stripslashes(var_export($route[2], true));
                }
            } else {
                $routeUrl = $route;
            }
            $ruleName = $routeUrl;
            $query = [];
            if (strpos($routeUrl, '?') > 0) {
                $routeUrlArr = parse_url($routeUrl);
                $routeUrl = $routeUrlArr['path'];
                parse_str($routeUrlArr['query'], $query);
            }

            $routeCode = "Route::get('$rule', '$routeUrl')";
            $routeCode .= "->name('$ruleName')";

            if (!empty($query)) {
                $query = var_export($query, true);
                $query = str_replace(["\n", 'array (  '], ['', 'array('], $query);
                $routeCode .= "->append($query)";
            }

            if (!empty($pattern)) {
                $pattern = str_replace(["\n", 'array (  '], ['', 'array('], $pattern);
                $routeCode .= "\n->pattern($pattern)";
            }

            $routeCode .= ";\n";
            $customerStr [] = $routeCode;
        }
        $customerStr[] = "})->prefix('frontend.');";
        $fileStr = array_merge($fileStr,$customerStr);
        $sysDomain = env('app_host');
        $sysDomain = parse_url($sysDomain);
        if(!empty($sysDomain['host']) && $sysDomain['host'] == $websiteDomain &&  $lang == "zh"){
            $adminRoute = app()->getRootPath() . 'route' . DIRECTORY_SEPARATOR . 'admin.php';
            $admin_route = file($adminRoute);
            foreach ($admin_route as $key => $val){
                if(trim($val) == "<?php" || trim($val) == "use think\\facade\\Route;"){
                    unset($admin_route[$key]);
                }
            }
            $fileStr = array_merge($fileStr,$admin_route);
        }
        array_push($fileStr,"});");

        $content = join("\n", $fileStr);
        $path = $this->createRoutePath($siteId,$lang);
        // 前台页面路由
        $th = fopen($path['frontend'],'w');
        file_put_contents($path['frontend'], $content . "\n\n");
        fclose($th);
        return $cacheRoutes;
    }

    public function createRoutePath($siteId,$lang): array
    {
        $routeDir = app()->getRootPath() . "route";
        if (!file_exists($routeDir)) {
            mkdir($routeDir);
        }

        $apiRouteFile = $routeDir.DIRECTORY_SEPARATOR .$siteId .'_' .$lang . "_api.php";
        $frontendRouteFile = $routeDir .DIRECTORY_SEPARATOR .$siteId.'_' .$lang . "_frontend.php";
        return [
            'frontend' => $frontendRouteFile,
            'api'   => $apiRouteFile,
        ];
    }

    public function getUrl($action, $vars)
    {
        $fullUrl = $this->buildFullUrl($action, $vars);

        $url = $this->where('full_url', $fullUrl)->value('url');

        return empty($url) ? '' : $url;
    }

    public function getFullUrlByUrl($url)
    {
        $full_url = $this->where('url', $url)->value('full_url');

        return empty($full_url) ? '' : $full_url;

    }

    public function getFullUrl($where): array
    {
        $full_url = $this->where($where)->column('full_url');

        return empty($full_url)? [] : $full_url;
    }

    public function buildFullUrl($action, $vars): string
    {
        // 解析参数
        if (is_string($vars)) {
            // aaa=1&bbb=2 转换成数组
            parse_str($vars, $vars);
        }
        if (!empty($vars)) {
            ksort($vars);
            $fullUrl = $action . '?' . http_build_query($vars);
        } else {
            $fullUrl = $action;
        }
        return $fullUrl;
    }

    public function existsRoute($url, $fullUrl): bool
    {
        $findRouteCount = $this->where('url', $url)->whereNotLike('full_url', $fullUrl)->count();

        return $findRouteCount > 0;
    }


    /**
     * @throws ModelException
     */
    public function setRoute($url, $action, $vars,$lang, $type, $sort, $seller_id, $category_id,$siteId,$category_title = '',$pattern=''): array
    {
        if (preg_match("/[()'\";]/", $url)) {
            return dataReturn(-1, 'url格式错误');
        }
        $fullUrl = $this->buildFullUrl($action, $vars);

        $findRoute = $this->exitRoute(['seller_id'=>$seller_id,'website_id'=>$siteId,'lang'=>$lang,'full_url'=>$fullUrl])['data'];
        if (!empty($findRoute)) {
            if (empty($url)) {
                $data = $this->delRoute(['id' => $findRoute['id'], 'seller_id' => $seller_id]);
            } else {
                $updateData = [
                    'url' => $url,
                    'sort' => $sort,
                    'type' => $type,
                    'category_id' => $category_id,
                    'pattern' => $pattern
                ];
                $data = $this->updateRoute(['id' => $findRoute['id'], 'seller_id' => $seller_id], $updateData);
            }
        } else {
            if (!empty($url)) {
                $addData = [
                    'seller_id' => $seller_id,
                    'full_url' => $fullUrl,
                    'website_id' => $siteId,
                    'url' => $url,
                    'sort' => $sort,
                    'type' => $type,
                    'lang' => $lang,
                    'category_title' => $category_title,
                    'category_id' => $category_id,
                    'pattern' => $pattern
                ];
                $data = $this->addRoute($addData);

            } else {
                $data = [$this->sucCode, $this->getMsg];
            }
        }

        return $data;

    }

    /**
     * @param $action
     * @param $vars
     * @return bool
     * @throws \Exception
     */
    public function deleteRoute($action, $vars): bool
    {
        $fullUrl = $this->buildFullUrl($action, $vars);
        $this->where('full_url', $fullUrl)->delete();
        return true;
    }
}